import { useWebSocket } from '@vueuse/core'
import { computed, ref, watch } from 'vue'

// 参数类型
export interface IUseWebSocketOptions {
  isAutoReconnect?: boolean
  heartbeatInterval?: number
  heartbeatMsg?: string
  heartbeatResponseMsg?: string
  pongTimeout?: number
}

// 消息处理函数类型
type MessageHandler = (payload: any) => void

/**
 * 通用 WebSocket 封装（支持自动重连、心跳）
 */
export function useWebSocketClient(url: string, options: IUseWebSocketOptions = {}) {
  // 参数
  const {
    isAutoReconnect = true,
    heartbeatInterval = 30000,
    heartbeatMsg = 'ping',
    heartbeatResponseMsg = 'pong',
    pongTimeout = 35000,
  } = options

  // 消息列表
  const messageList = ref<string[]>([])

  // 注册消息处理函数
  const handlers = new Map<string, MessageHandler>()

  const { status, data, send, open, close } = useWebSocket(url, {
    immediate: true, // 立即连接
    autoConnect: true, // 自动连接,当 url 发生更改时，它会自动重新连接到新的 url
    autoClose: true, // 当连接关闭时，自动关闭 WebSocket
    autoReconnect: {
      // 自动重连，手动调用 close 时不会重连
      retries: isAutoReconnect ? 3 : 0,
      delay: 1000,
      onFailed: () => {
        console.log('[WebSocket] 3次重连失败')
      },
    },
    onConnected: () => {
      console.log('[WebSocket] 已连接')
    },
    onDisconnected: () => {
      console.log('[WebSocket] 断开连接')
    },
    onError: (e) => {
      console.error('[WebSocket] 连接出错:', e)
    },
    onMessage: (e) => {
      console.log('[WebSocket] 收到消息:', e)
    },
    heartbeat: {
      // 心跳检测，检测客户端与服务器之间是否保持活跃连接，避免因长时间无数据传输而被服务器或中间设备（如防火墙）断开连接
      message: heartbeatMsg, // 客户端发送给服务器的心跳消息内容
      interval: heartbeatInterval, // 发送心跳的时间间隔
      responseMessage: heartbeatResponseMsg, // 服务端需要返回的心跳回复内容，如果服务端返回的内容与 responseMessage 不匹配，则认为连接已断开
      pongTimeout: pongTimeout, // 等待服务器回复的时间，如果超过这个时间还没有收到服务器的回复，则认为连接已断开
    },
    protocols: [], // 要使用的一个或多个子协议的列表
  })

  /**
   * 收到消息
   */
  watch(data, (val) => {
    if (val) {
      messageList.value.push(val)
      console.log('[WebSocket] 收到消息messageList:', messageList.value)
    }
  })

  /**
   * 注册消息处理函数
   * @param type 消息类型
   * @param handler 消息处理函数
   */
  const registerHandler = (type: string, handler: MessageHandler) => {
    handlers.set(type, handler)
  }

  return {
    // 原始能力
    send,
    close,
    open,
    status,
    data,

    // 拓展能力
    messageList,
    isReady: computed(() => status.value === 'OPEN'),
    registerHandler,
  }
}
